package net.oschina.archx.spring.mybatis.type;

import com.alibaba.fastjson.JSON;
import org.apache.ibatis.type.BaseTypeHandler;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.MappedJdbcTypes;
import org.apache.ibatis.type.MappedTypes;

import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;

/**
 * 简单Json类型处理器
 *
 * @author Archx[archx@foxmail.com]
 * @date 2016/2/25 0025
 */
@MappedTypes({List.class, Map.class})
@MappedJdbcTypes({JdbcType.VARCHAR, JdbcType.LONGVARCHAR})
public class JsonTypeHandler extends BaseTypeHandler<Object> {
    /**
     * JSON与类名之间的分隔符
     */
    static final String JSON_CLASSNAME_SEPARATOR = "__$$$__";

    @Override
    public void setNonNullParameter(PreparedStatement preparedStatement, int i, Object o, JdbcType jdbcType) throws SQLException {
        String json = JSON.toJSONString(o);
        json = json + JSON_CLASSNAME_SEPARATOR + o.getClass().getName();
        preparedStatement.setString(i, json);
    }

    @Override
    public Object getNullableResult(ResultSet resultSet, String s) throws SQLException {
        return jsonToObject(resultSet.getString(s));
    }

    @Override
    public Object getNullableResult(ResultSet resultSet, int i) throws SQLException {
        return jsonToObject(resultSet.getString(i));
    }

    @Override
    public Object getNullableResult(CallableStatement callableStatement, int i) throws SQLException {
        return jsonToObject(callableStatement.getString(i));
    }

    /**
     * 反序列化
     *
     * @param text
     * @return
     */
    private Object jsonToObject(String text) {
        if (text == null || "".equals(text)) return null;

        int index = text.lastIndexOf(JSON_CLASSNAME_SEPARATOR);
        // 没有类名
        if (index < 0) return null;

        // JSON 数据
        String json = text.substring(0, index);
        // 类名
        String className = text.substring(index + JSON_CLASSNAME_SEPARATOR.length(), text.length());

        Class<?> clazz;
        try {
            clazz = Class.forName(className);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("JSON 转换对象时出错，没有找到类型：" + className);
        }
        return JSON.parseObject(json, clazz);
    }
}
